/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.aljfce.business.mail.control;

import com.aljfce.business.entity.Event;
import com.aljfce.business.entity.User;
import com.aljfce.business.entity.WeatherInformation;
import com.aljfce.business.mail.exception.InvalidMessageException;
import com.aljfce.business.mail.exception.InvalidRecipientException;
import com.aljfce.business.mail.exception.InvalidSubjectException;
import java.text.SimpleDateFormat;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

/**
 *
 * @author Jacopo Ferrigno <jacopo.ferrigno@gmail.com>
 */
@Stateless
public class MailManager {

    @Resource(name ="java:app/mail/meteocalServiceMail")
    private Session mailSession;

    private static final String subjectPrefix = "[meteocal] ";

    SimpleDateFormat simpleDateFormatter;

    @PostConstruct
    void init() {
        this.simpleDateFormatter = new SimpleDateFormat("EEEE, dd/MM/yyyy 'at' HH:mm ");
    }

    /**
     * Use this method to send an email message after a successful registration
     * of a user.
     *
     * @param receiver The {@link User} object representing the receiver, must
     * be not null
     * @param password The user's password
     * @throws IllegalArgumentException if the receiver is null
     * @throws MessagingException if the sending of the message fail.
     * @throws InvalidSubjectException if the subject is not a valid String
     * @throws InvalidRecipientException if the user email is not a valid one.
     * @throws InvalidMessageException if the body of the message is not valid
     */
    @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
    public void sendRegistrationMsg(User receiver, String password) throws IllegalArgumentException, MessagingException, InvalidSubjectException, InvalidRecipientException, InvalidMessageException {
        if (receiver == null) {
            throw new IllegalArgumentException("User cannot be null");
        }

        String subject = MailManager.subjectPrefix + "Welcome to Meteocal " + receiver.getName();
        String message = "You have successfully registered to meteocal.\n\n"
                + "Your access data are: \n"
                + "Username: " + receiver.getEmail() + "\n"
                + "Password: " + password + "\n";

        this.sendMail(receiver.getEmail(), subject, message);

    }

    /**
     * Use this method to send an email message when the Weather conditions for
     * an event have changed.
     *
     * @param receiver The {@link User} object representing the receiver, must
     * be not null
     * @param event The {@link Event} object representing the event, must be not
     * null
     * @param weather The {@link WeatherInformation} object representing the
     * weather conditions, must be not null
     * @throws IllegalArgumentException if one of the parameters is null.
     */
    @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
    public void sendWeatherChangedMsg(User receiver, Event event, WeatherInformation weather) throws IllegalArgumentException {
        this.checkParametersNotNull(receiver, event, weather);

        String subject = MailManager.subjectPrefix + "Weather changed";
        String message = "The weather conditions for your event in " + event.getLocation() + ".\n"
                + "Starting on date " + this.simpleDateFormatter.format(event.getStartingDate())
                + "and ending on date" + this.simpleDateFormatter.format(event.getEndingTime())
                + "has changed to " + weather.getDetails() + ".\n";
        try {
            this.sendMail(receiver.getEmail(), subject, message);
        } catch (MessagingException ex) {
            Logger.getLogger(MailManager.class.getName()).log(Level.SEVERE, "In sendWeaterChangeMsg {0}", ex);
        } catch (InvalidSubjectException | InvalidRecipientException | InvalidMessageException ex) {
            Logger.getLogger(MailManager.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

    /**
     * Use this method to send an email message when the Weather conditions for
     * an event, which will take place in the next 3 days have changed.
     *
     * @param receiver The {@link User} object representing the receiver, must
     * be not null
     * @param event The {@link Event} object representing the event, must be not
     * null
     * @param weather The {@link WeatherInformation} object representing the
     * weather conditions, must be not null
     * @throws IllegalArgumentException if one of the parameters is null.
     */
    @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
    public void send3DayNotificationMsg(User receiver, Event event, WeatherInformation weather) {
        this.checkParametersNotNull(receiver, event, weather);

        String subject = MailManager.subjectPrefix + "Weather changed for event in next 3 days";
        String message = "The weather conditions for your event in " + event.getLocation()
                + " that will take place in the next three days.\n"
                + "Starting on date " + this.simpleDateFormatter.format(event.getStartingDate())
                + "and ending on date" + this.simpleDateFormatter.format(event.getEndingTime())
                + "has changed to " + weather.getDetails() + ".\n";

        try {
            this.sendMail(receiver.getEmail(), subject, message);
        } catch (MessagingException ex) {
            Logger.getLogger(MailManager.class.getName()).log(Level.SEVERE, "In send3DayNotificationMsg {0}", ex);
        } catch (InvalidSubjectException | InvalidRecipientException | InvalidMessageException ex) {
            Logger.getLogger(MailManager.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

    /**
     * Use this method to send an email message when the Weather conditions for
     * an event that will take place tomorrow have changed.
     *
     * @param receiver The {@link User} object representing the receiver, must
     * be not null
     * @param event The {@link Event} object representing the event, must be not
     * null
     * @param weather The {@link WeatherInformation} object representing the
     * weather conditions, must be not null
     * @throws IllegalArgumentException if one of the parameters is null.
     */
    @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
    public void send1DayNotificationMsg(User receiver, Event event, WeatherInformation weather) {
        this.checkParametersNotNull(receiver, event, weather);

        String subject = MailManager.subjectPrefix + "Weather changed for tomorrow event";
        String message = "The weather conditions for your event in " + event.getLocation()
                + " that will take place tomorrow.\n"
                + "Starting on date " + this.simpleDateFormatter.format(event.getStartingDate())
                + "and ending on date" + this.simpleDateFormatter.format(event.getEndingTime())
                + "has changed to " + weather.getDetails() + ".\n";

        try {

            this.sendMail(receiver.getEmail(), subject, message);
        } catch (MessagingException ex) {
            Logger.getLogger(MailManager.class.getName()).log(Level.SEVERE, "In send1DayNotificationMsg {0}", ex);
        } catch (InvalidSubjectException | InvalidRecipientException | InvalidMessageException ex) {
            Logger.getLogger(MailManager.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

    /**
     * Use this method to send the invitation mail for a given event and a given user.
     *  
     * 
     * @param receiver a {@link User} object representing the user to send the message
     * @param event an {@link Event} object representing the event from which extract informations
     * @throws IllegalArgumentException if any of the arguments is null or any of its importan files is nullt
     */
    @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
    public void sendInvitationNotificationMsg(User receiver, Event event) {
        this.checkParametersNotNull(receiver, event);

        String subject = MailManager.subjectPrefix + "You have been invited to event: " + event.getTitle();
        String message = "You have been invited from  " + event.getCreator().getName() + " " + event.getCreator().getSurname()
                + " to event " + event.getTitle()
                + "\nStarting on date " + this.simpleDateFormatter.format(event.getStartingDate())
                + "and ending on date " + this.simpleDateFormatter.format(event.getEndingTime())
                + ".\n";
        if (event.getDescription() != null && !event.getDescription().isEmpty()) {
            message = message + "\n\n"
                    + "Description:\n" + event.getDescription();
        }

        try {

            this.sendMail(receiver.getEmail(), subject, message);
        } catch (MessagingException ex) {
            Logger.getLogger(MailManager.class.getName()).log(Level.SEVERE, "In sendInvitationNotificationMsg {0}", ex);
        } catch (InvalidSubjectException | InvalidRecipientException | InvalidMessageException ex) {
            Logger.getLogger(MailManager.class.getName()).log(Level.SEVERE, null, ex);
        }

    }
    @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
    private void sendMail(String email, String subject, String body) throws MessagingException, InvalidSubjectException, InvalidRecipientException, InvalidMessageException {
        MimeMessage message = new MimeMessage(mailSession);

        try {
            message.setSubject(subject);
        } catch (MessagingException messagingException) {
            throw new InvalidSubjectException(messagingException.getMessage());
        }
        try {
            message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(email, false));
        } catch (MessagingException messagingException) {
            throw new InvalidRecipientException(messagingException.getMessage());
        }

        try {
            message.setText(body);
        } catch (MessagingException messagingException) {
            throw new InvalidMessageException(messagingException.getMessage());
        }
        Transport.send(message);
    }

    @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
    private void checkParametersNotNull(User receiver, Event event, WeatherInformation weather) throws IllegalArgumentException {
        this.checkParametersNotNull(receiver, event);
        if (weather == null) {
            throw new IllegalArgumentException("weather cannot be null");
        }
    }
    @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
    private void checkParametersNotNull(User receiver, Event event) throws IllegalArgumentException {
        if (receiver == null) {
            throw new IllegalArgumentException("User cannot be null");
        }
        if (event == null) {
            throw new IllegalArgumentException("event canot be null");
        }

    }

}
